//
// CDeviceObserver.cpp
//

/*-----------------------------------------------------*\
			HQ Tech, Make Technology Easy!       
 More information, please go to http://hqtech.nease.net.
/*-----------------------------------------------------*/

#include "stdafx.h"
#include "Dbt.h"
#include <streams.h>
#include "CDeviceObserver.h"
#include "GlobalDefs.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDeviceObserver
IMPLEMENT_DYNCREATE(CDeviceObserver, CFrameWnd)

CDeviceObserver::CDeviceObserver()
{
	mEventType = 0;
	mEventData = NULL;
}

CDeviceObserver::~CDeviceObserver()
{
	if (mEventData)
	{
		delete[] mEventData;
		mEventData = NULL;
	}
}

void CDeviceObserver::Register(void)
{
	DEV_BROADCAST_DEVICEINTERFACE filterData;
	ZeroMemory(&filterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
	
	filterData.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
	filterData.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
	filterData.dbcc_classguid = AM_KSCATEGORY_CAPTURE;

	mUnregisterDeviceNotification = NULL;
	mRegisterDeviceNotification = NULL;
	// dynload device removal APIs
	{
		HMODULE hmodUser = GetModuleHandle(TEXT("user32.dll"));
		ASSERT(hmodUser);	   // we link to user32
		mUnregisterDeviceNotification = (PUnregisterDeviceNotification)
										GetProcAddress(hmodUser, "UnregisterDeviceNotification");

		// m_pRegisterDeviceNotification is prototyped differently in unicode
		mRegisterDeviceNotification = (PRegisterDeviceNotification)
							GetProcAddress(hmodUser,
#ifdef UNICODE
						   "RegisterDeviceNotificationW"
#else
						   "RegisterDeviceNotificationA"
#endif
						   );
		// failures expected on older platforms.
		ASSERT(mRegisterDeviceNotification && mUnregisterDeviceNotification ||
			   !mRegisterDeviceNotification && !mUnregisterDeviceNotification);
	}

	mNotifyHandle = NULL;

	if (mRegisterDeviceNotification)
	{
		mNotifyHandle = mRegisterDeviceNotification(this->GetSafeHwnd(), &filterData, DEVICE_NOTIFY_WINDOW_HANDLE);
		ASSERT(mNotifyHandle != NULL);
	}
}

void CDeviceObserver::Unregister(void)
{
	if (mNotifyHandle != NULL)
	{
		ASSERT(mUnregisterDeviceNotification);
		mUnregisterDeviceNotification(mNotifyHandle);
		mNotifyHandle = NULL;
	}
}

BEGIN_MESSAGE_MAP(CDeviceObserver, CFrameWnd)
	//{{AFX_MSG_MAP(CDeviceObserver)
	ON_WM_CREATE()
	ON_WM_CLOSE()
	ON_WM_DEVICECHANGE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDeviceObserver message handlers
int CDeviceObserver::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	int createResult = CFrameWnd::OnCreate(lpCreateStruct);
	if (createResult != -1)
	{
		Register();
	}
	return createResult;
}
	
void CDeviceObserver::OnClose() 
{
	Unregister();
	CFrameWnd::OnClose();
}

BOOL CDeviceObserver::OnDeviceChange(UINT nEventType, DWORD dwData)
{
	// We are interested in only device arrival & removal events
	if (DBT_DEVICEARRIVAL != nEventType && DBT_DEVICEREMOVECOMPLETE != nEventType)
		return CWnd::OnDeviceChange (nEventType, dwData);

	PDEV_BROADCAST_HDR pdbh = (PDEV_BROADCAST_HDR) dwData;
	if (pdbh->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE)
	{
		return CWnd::OnDeviceChange (nEventType, dwData);
	}
	PDEV_BROADCAST_DEVICEINTERFACE pdbi = (PDEV_BROADCAST_DEVICEINTERFACE) dwData;
	if (pdbi->dbcc_classguid != AM_KSCATEGORY_CAPTURE)
	{
		return CWnd::OnDeviceChange (nEventType, dwData);
	}

	mEventType = nEventType;
	if (mEventData)
	{
		delete[] mEventData;
		mEventData = NULL;
	}
	mEventData = new BYTE[pdbh->dbch_size];
	memcpy(mEventData, pdbh, pdbh->dbch_size);
	pdbi = (PDEV_BROADCAST_DEVICEINTERFACE) mEventData;

	if (nEventType == DBT_DEVICEARRIVAL)
	{
		Broadcast(msg_PnPDeviceAdded, (void *)pdbi->dbcc_name, NULL);
	}
	else if (nEventType == DBT_DEVICEREMOVECOMPLETE)
	{
		Broadcast(msg_PnPDeviceRemoved, (void *)pdbi->dbcc_name, NULL);
	}

	return CWnd::OnDeviceChange (nEventType, dwData);
}
